package com.lu.study.lu.mybatis.plus.controller;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.lu.study.lu.api.response.ResponseBody;
import com.lu.study.lu.mybatis.plus.service.impl.BaseServiceImpl;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.SneakyThrows;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @autor 10758
 * @system lu-pro-arch
 * @Time 2018/12/6
 */
@Api("所有controller基类 泛型S 代表service 泛型D代表dto ,E 代表 entity")
public class BaseController<S extends BaseServiceImpl, E, D, ID extends Serializable> {

    @Autowired
    protected S service;

    /**
     * 获取 entity 具体类型
     *
     * @return
     */
    protected Class<E> entityClass() {
        return (Class<E>) ReflectionKit.getSuperClassGenericType(this.getClass(), 1);
    }

    /**
     * 获取 dto 具体类型
     *
     * @return
     */
    protected Class<D> dtoClass() {
        return (Class<D>) ReflectionKit.getSuperClassGenericType(this.getClass(), 2);
    }


    @PostMapping(path = "/save", produces = "application/json;charset=UTF-8")
    @ApiOperation(value = "单个保存", notes = "单个保存")
    public ResponseBody<D> save(@RequestBody D dto) {
        E entity = dto2Entity(dto);
        boolean res = service.save(entity);
        if (!res) {
            return ResponseBody.failed("插入失败");
        }
        return ResponseBody.ok(entity2Dto(entity));
    }

    @SneakyThrows
    private <D> E dto2Entity(D dto) {
        E e = (E) entityClass().newInstance();
        ModelMapper modelMapper = new ModelMapper();
        modelMapper.map(dto, e);
        return e;
    }

    @SneakyThrows
    private <D, E> D entity2Dto(E e) {
        D d = (D) dtoClass().newInstance();
        ModelMapper modelMapper = new ModelMapper();
        modelMapper.map(e, d);
        return d;
    }

    @PostMapping("/save-batch")
    @ApiOperation(value = "批量保存", notes = "批量保存")
    public <D> ResponseBody<List<D>> saveBatch(@RequestBody List<D> dtoList) {
        List<E> eList = dtoList.stream().map(this::dto2Entity).collect(Collectors.toList());
        service.saveBatch(eList);
        return ResponseBody.ok(entity2Dto(eList));

    }

    private <D> List<D> entity2Dto(List<E> entitys) {
        if (null == entitys || 0 == entitys.size()) {
            return null;
        }
        final List<D> dList = new ArrayList<>();
        entitys.stream().forEach(e -> dList.add(entity2Dto(e)));
        return dList;
    }


    @PostMapping("/save-or-update")
    @ApiOperation(value = "保存或者更新", notes = "保存或者更新")
    public ResponseBody<Boolean> saveOrUpdate(@RequestBody D dto) {
        return ResponseBody.ok(service.saveOrUpdate(dto2Entity(dto)));
    }

    @PostMapping("/save-or-update-batch")
    @ApiOperation(value = "批量保存或者批量更新", notes = "批量保存或者批量更新")
    public ResponseBody<Boolean> saveOrUpdateBatch(@RequestBody List<D> dtoList) {
        List<E> eList = dtoList.stream().map(this::dto2Entity).collect(Collectors.toList());
        return ResponseBody.ok(service.saveOrUpdateBatch(eList));
    }

    @PostMapping("/remove-by-id")
    @ApiOperation(value = "通过主键删除", notes = "通过主键删除")
    public ResponseBody<Boolean> removeById(@RequestBody ID id) {
        return ResponseBody.ok(service.removeById(id));
    }

    @PostMapping("/remove-by-map")
    @ApiOperation(value = "通过map删除1", notes = "通过map删除")
    public ResponseBody<Boolean> removeByMap(@RequestBody Map<String, Object> columnMap) {
        return ResponseBody.ok(service.removeByMap(columnMap));
    }

    @PostMapping("/remove")
    @ApiOperation(value = "通过条件删除", notes = "通过条件删除")
    public ResponseBody<Boolean> remove(@RequestBody Wrapper<E> wrapper) {
        return ResponseBody.ok(service.remove(wrapper));
    }

    @PostMapping("/remove-by-ids")
    @ApiOperation(value = "通过主键集合删除", notes = "通过主键集合删除")
    public ResponseBody<Boolean> removeByIds(@RequestBody Collection<ID> idList) {
        return ResponseBody.ok(service.removeByIds(idList));
    }

    @PostMapping("/update-by-id")
    @ApiOperation(value = "通过主键更新", notes = "通过主键更新")
    public ResponseBody<Boolean> updateById(@RequestBody D dto) {
        return ResponseBody.ok(service.updateById(dto2Entity(dto)));
    }

    @PostMapping("/update")
    @ApiOperation(value = "通过条件更新", notes = "通过条件更新，第一个参数：更新后的实体，第二个参数：更新条件")
    public ResponseBody<Boolean> update(D dto, Wrapper<E> updateWrapper) {
        return ResponseBody.ok(service.update(entity2Dto(dto), updateWrapper));
    }

    @PostMapping("/update-by-ids")
    @ApiOperation(value = "通过主键集合更新", notes = "通过主键集合更新")
    public ResponseBody<Boolean> updateBatchById(@RequestBody List<D> dtoList) {
        List<E> eList = dtoList.stream().map(this::dto2Entity).collect(Collectors.toList());
        return ResponseBody.ok(service.updateBatchById(eList));
    }

    @GetMapping(value = "/get-by-id/{id}")
    @ApiOperation(value = "通过主键获取记录", notes = "通过主键获取记录")
    public ResponseBody<D> getById(@PathVariable ID id) {
        return ResponseBody.ok(entity2Dto(service.getById(id)));
    }

    @PostMapping("/get-by-ids")
    @ApiOperation(value = "通过主键集合获取记录", notes = "通过主键集合获取记录")
    public ResponseBody<Collection<D>> listByIds(@RequestBody Collection<ID> idList) {
        return ResponseBody.ok(entity2Dto(service.listByIds(idList)));
    }

    @PostMapping("/get-by-map")
    @ApiOperation(value = "通过map获取记录", notes = "通过map获取记录")
    public ResponseBody<List<D>> listByMap(@RequestBody Map<String, Object> columnMap) {
        return ResponseBody.ok(entity2Dto(service.listByMap(columnMap)));
    }

    @PostMapping("/get-one")
    @ApiOperation(value = "通过条件获取唯一一条记录", notes = "通过条件获取唯一一条记录")
    public ResponseBody<D> getOne(@RequestBody Wrapper<E> queryWrapper) {
        return ResponseBody.ok(entity2Dto(service.getOne(queryWrapper)));
    }

    @PostMapping("/count")
    @ApiOperation(value = "根据条件进行数据量统计", notes = "根据条件进行数据量统计")
    public ResponseBody<Integer> count(@RequestBody Wrapper<E> queryWrapper) {
        return ResponseBody.ok(service.count(queryWrapper));
    }

    @PostMapping("/list")
    @ApiOperation(value = "根据条件查询", notes = "根据条件查询")
    public ResponseBody<List<D>> list(@RequestBody Wrapper<E> queryWrapper) {
        return ResponseBody.ok(entity2Dto(service.list(queryWrapper)));
    }

    @PostMapping("/page")
    @ApiOperation(value = "根据条件分页", notes = "根据条件分页")
    public ResponseBody<Page<E>> page(@RequestBody Page<E> page) {
        return ResponseBody.ok((Page<E>) service.page(page));
    }

}
